/* A simple server in the internet domain using TCP
   The port number is passed as an argument */

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <strings.h>
#include <signal.h>
#include <string>
#include <pthread.h>
#include <queue>
#include <list>
#include <sys/time.h>

#include "definitions.hpp"

using namespace std;


unsigned char dupBuffer[2500];
unsigned char dupBuffer_tcp[2500];
int last_pack;
long fsize;

//Global Declarations of Locks begin ------------------------------->

     pthread_mutex_t synch_lock;
     pthread_cond_t wakeup_udp;
	 pthread_cond_t sleep_cond;
     pthread_mutex_t sleep_lock;


//Global Declarations of Locks end --------------------------------->

Data* d1;
bool file_complete_flag = 0;
uint32_t num_packets = 0;
FILE *fp;
FILE *fp1;
double mytime(void)
{
    struct timeval tv;
    double currtime=0;
    gettimeofday(&tv,NULL);
    currtime=((double)(tv.tv_sec)*1000.0) + ((double)(tv.tv_usec)/1000.0);
    return currtime;
}
void error(const char *msg)
{
    perror(msg);
}

//Checks whether a socket is ready or not
int sock_ready(int sock)
{
    int             res;
    fd_set          sready;
    struct timeval  nowait;

    nowait.tv_usec=100;
    FD_ZERO(&sready);
    FD_SET((unsigned int)sock,&sready);

    memset((char *)&nowait,0,sizeof(nowait));


    res = select(sock+1,&sready,NULL,NULL,&nowait);
    if( FD_ISSET(sock,&sready) )
        res = 1;
    else
        res = 0;

    return(res);
}



// Multithreaded Programming begin ---------------------------------->

// Moved to separate files

// Multithreaded Programming end ---------------------------------->


//Process Kill : Begin
int number_processes = 0;


class my_process
{
	public:
	int pro_id;
	int sock_no;
};
my_process process_arr[100];

/*int tron=0;
// Process Kill : End

//Signal Handling : Begin

void SignalHandler_sigint(int sig)
{
	cout<<"Signal SIGINT received, the program will gracefully terminate now!"<<endl;

   for(int x=0;x<tron;x++)
   {
	   kill(process_arr[x].pro_id,SIGUSR1);
   }

    close(sockfd);

	exit(1);
}
*/
int main(int argc, char *argv[])
{

	 signal(SIGPIPE, SIG_IGN);

	 //Initializing Locks Begin-------------------------------------------------->

     pthread_mutex_init(&synch_lock,NULL);
     pthread_cond_init(&wakeup_udp,NULL);
	 pthread_mutex_init(&sleep_lock,NULL);
     pthread_cond_init(&sleep_cond,NULL);


	 //Initializing Locks End---------------------------------------------------->

     if (argc < 3) {
         fprintf(stderr,"ERROR, no port provided\n");
         exit(1);
     }

	 string hname = string(argv[1]);
    string str = string(argv[2]);
	int portno = atoi(str.c_str());

	  /*FILE* fp1 = fopen("Output","wb");
	  fclose(fp1);*/

      fp = fopen("Output","wb");
	  fp1 = fopen("Output","wb");

	 //Begin Class Data Declarations ----------------------------------------------->
	  d1 = new Data(hname,portno,0,NULL);
     //End Class Data Declarations ----------------------------------------------->


     //TCP thread for receiving the header information --------------------------BEGIN>
     cout<<d1->getPortNum()<<d1->getHostname()<<endl;

            pthread_t tcp_thread;
            pthread_attr_t attr_tcp;
            int thrd_tcp=0;
            void* status_tcp;
            
            pthread_attr_init(&attr_tcp);
            pthread_attr_setdetachstate(&attr_tcp, PTHREAD_CREATE_JOINABLE);
            
            thrd_tcp=pthread_create(&tcp_thread,&attr_tcp,tcp_thread_server_func,(void *)d1);
            if(thrd_tcp){
                cerr<<"Error; return code from thread tcp create call is"<<thrd_tcp<<endl;
                exit(-1);
            } 
            
            pthread_attr_destroy(&attr_tcp);
            
            
            // BEGIN UDP thread here ----------------------------------->
            
            pthread_t udp_thread;
            pthread_attr_t attr_udp;
            int thrd_udp=0;
            void* status_udp;
            
            pthread_attr_init(&attr_udp);
            pthread_attr_setdetachstate(&attr_udp, PTHREAD_CREATE_JOINABLE);
            
            thrd_udp=pthread_create(&udp_thread,&attr_udp,udp_thread_server_func,(void *)d1);
            if(thrd_udp != 0){
                cerr<<"Error; return code from thread udp create call is"<<thrd_udp<<endl;
                exit(-1);
            } 
            
            pthread_attr_destroy(&attr_udp);


          

            thrd_udp=pthread_join(udp_thread,&status_udp);
            if(thrd_udp){
                cerr<<"Error; return code from thread tcp join call is "<<thrd_udp<<endl;
                exit(-1);
            }
    cout<<"udpthreadjoin"<<endl;

			thrd_tcp=pthread_join(tcp_thread,&status_tcp);
            if(thrd_tcp){
                cerr<<"Error; return code from thread tcp join call is "<<thrd_tcp<<endl;
                exit(-1);
            }
    cout<<"tcpthreadjoin"<<endl;

            // END UDP thread here ----------------------------------->
       
		//Begin Destroy Locks and CVs ------------------------------------------->
     pthread_mutex_destroy(&synch_lock);
	 pthread_cond_destroy(&wakeup_udp);
	 pthread_mutex_destroy(&sleep_lock);
	 pthread_cond_destroy(&sleep_cond);
	 
	 //End Destroy Locks and CVs --------------------------------------------->
    cout<<"main exiting"<<endl;
/*	fflush(fp);
    fclose(fp);
	fflush(fp1);
    fclose(fp1);
  */  return 0; 
}
